import json
import os
import time

from cf.dry_box import DryBox
# from cf.power_resume import PowerResume
from cf.tare import Tare
from cf.utils import MsgBroadUdp


class CfDev:
    def __init__(self, config):
        help.log("初始化CfDev")
        self.printer = config.get_printer()
        self.config = config
        self.gcode = self.printer.lookup_object('gcode')
        self.gcmd = self.gcode.create_gcode_command("", "", {})
        self.dry_box = DryBox(self.gcmd, interval=0.5)
        self.printer.register_event_handler("klippy:ready", self.handle_ready)
        self.BED_MESH_Z_OFFSET = self.config.getfloat("bed_mesh_z_offset", 0)
        self.enable_calc_damping = self.config.getboolean("enable_calc_damping", False)
        self.states = {'shutdown_after_print_complete': self.config.getfloat("shutdown_after_print_complete", 0)}
        self.power_resume = None
        webhooks = self.printer.lookup_object('webhooks')
        webhooks.register_endpoint(
            "query/dry_box/status", self.query_dry_box_status)
        self.gcode.register_command("SHUTDOWN", self.cmd_SHUTDOWN,
                                    desc=self.cmd_SHUTDOWN_help)
        self.gcode.register_command("TARE", self.cmd_TARE,
                                    desc=self.cmd_TARE_help)
        self.gcode.register_command("SET_VAL", self.cmd_SET_VAL,
                                    desc=self.cmd_SET_VAL_help)
        # 设备在关机后，mcu没有关，使用firmware_restart来重启下mcu
        self.printer.send_event("klippy:firmware_restart")
        self.tmc_command_helpers = []

    def query_dry_box_status(self, web_request):
        web_request.send({"data": self.dry_box.last_msg, "data_time": self.dry_box.last_msg_time})

    def get_status(self, eventtime):
        power_resume_status = self.printer.lookup_object('power_resume_status')
        power_resume_enable = False
        if power_resume_status and power_resume_status.power_resume:
            if power_resume_status.power_resume.check_has_state_file():
                power_resume_enable = True
        return {"power_resume_enable": power_resume_enable}

    def handle_ready(self):
        # self.tare = Tare(self.printer, self.gcmd)

        # self.gcode.cmd_FIRMWARE_RESTART(self.gcmd)
        # 断电续打功能
        # try:
        #     self.gcmd.respond_info(f"PowerResume init")
        #     self.power_resume = PowerResume(self.printer)
        #     self.power_resume.start()
        # except Exception as e:
        #     self.gcmd.respond_info(f"PowerResume init error {e}")
        # 启动干燥盒数据获取打印线程
        try:
            self.dry_box.start_read_data_to_log()
        except Exception as e:
            self.gcmd.respond_info(f"start_read_data_to_log init error {e}")

        def handel_msg_send():
            return json.dumps(
                {"data": self.dry_box.last_msg, "data_time": self.dry_box.last_msg_time})

        try:
            MsgBroadUdp(handel_msg_send=handel_msg_send).start()
        except Exception as e:
            self.gcmd.respond_info(f"MsgBroadUdp init error {e}")

    def cmd_vibration(self, cmd):
        # 振动测试
        pass

    cmd_VIBRATION_help = "VIBRATION"

    def cmd_SET_VAL(self, gcmd):
        name = gcmd.get('NAME')
        val = gcmd.get('VAL')
        self.states[name] = val

    cmd_SET_VAL_help = "set cf_dev  val"

    # 关机命令
    def cmd_SHUTDOWN(self, cmd):
        # self.printer.invoke_shutdown("auto shutdown")
        os.system("shutdown now -h")

    cmd_SHUTDOWN_help = "shutdown"

    # 去皮命令
    def cmd_TARE(self, cmd):
        try:
            tare = Tare(self.printer, self.gcmd)
            tare.run()
            tare.ps.close()
        except Exception as e:
            self.gcmd.respond_info(f'tare fail:{e}')

    cmd_TARE_help = "TARE"

    def cmd_FORCE_STOP(self, gcmd):
        pass

    cmd_FORCE_STOP_help = ""

    def after_print_complete(self):
        try:
            shutdown_after_print_complete = self.states.get('shutdown_after_print_complete')
            if shutdown_after_print_complete is not None:
                timeout = float(shutdown_after_print_complete)
                idle_timeout_add = self.printer.lookup_object('idle_timeout_add', None)
                if idle_timeout_add and timeout > 0:
                    idle_timeout_add.set_shutdown_timeout(timeout, self.gcmd)
        except Exception as e:
            self.gcmd.respond_info(f"after_print_complete err:{e}")

    def after_print_cancel(self):
        pass
        # try:
        #     shutdown_after_print_complete = self.states.get('shutdown_after_print_complete')
        #     if shutdown_after_print_complete is not None:
        #         timeout = float(shutdown_after_print_complete)
        #         idle_timeout_add = self.printer.lookup_object('idle_timeout_add', None)
        #         if idle_timeout_add and timeout > 0:
        #             idle_timeout_add.set_shutdown_timeout(timeout, self.gcmd)
        # except Exception as e:
        #     self.gcmd.respond_info(f"after_print_complete err:{e}")

    def add_tmc_command_helper(self, tmc_command_helper):
        if tmc_command_helper not in self.tmc_command_helpers:
            self.tmc_command_helpers.append(tmc_command_helper)

    def tmc_force_stop(self):
        probe = self.printer.lookup_object('probe', None)
        motion_report = self.printer.lookup_object('motion_report')
        gcode_move = self.printer.lookup_object('gcode_move')
        reactor = self.printer.get_reactor()
        eventtime = reactor.monotonic()
        if motion_report.get_status(eventtime)['live_position'][2] < gcode_move.last_position[2]:
            # 是否在向上移动
            return
        if probe.probing:
            return
        if probe.bed_mesh_calibrating:
            return
        self.printer.invoke_shutdown("紧急停止，喷头压力超过阈值")

    def __tmc_force_stop(self):

        motion_report = self.printer.lookup_object('motion_report')
        gcode_move = self.printer.lookup_object('gcode_move')
        reactor = self.printer.get_reactor()
        eventtime = reactor.monotonic()
        # if motion_report.get_status(eventtime)['live_position'][2] < gcode_move.last_position[2]:
        #     # 是否在向上移动
        #     return
        # 可以获取当前位置来
        tmc_command_helpers = self.tmc_command_helpers
        toolhead = self.printer.lookup_object('toolhead')

        print_stats = self.printer.lookup_object('print_stats')

        if tmc_command_helpers:
            for tmc_command_helper in tmc_command_helpers:
                ch = tmc_command_helper.current_helper
                mcu = self.printer.lookup_object('mcu')
                reactor = self.printer.get_reactor()
                eventtime = reactor.monotonic()
                print_time = mcu.estimated_print_time(eventtime)
                ch.set_current(0.1, 0.1, print_time + 0.05)
            self.gcmd.respond_info('喷头检测到压力，紧急停止运动')
            #
            # last_speed_factor = gcode_move.speed_factor
            # gcode_move.speed = gcode_move._get_gcode_speed() * (3000. / (60. * 100.))
            # gcode_move.speed_factor = (3000. / (60. * 100.))
            #
            toolhead.wait_moves()
            if print_stats.state == 'printing':
                self.gcode.run_script("CANCEL_PRINT")
            self.gcode.run_script('M18')
            # gcode_move.speed = gcode_move._get_gcode_speed() * last_speed_factor
            # gcode_move.speed_factor = last_speed_factor
            self.tmc_start()

    def tmc_start(self):
        tmc_command_helpers = self.tmc_command_helpers
        if tmc_command_helpers:
            for tmc_command_helper in tmc_command_helpers:
                ch = tmc_command_helper.current_helper
                # toolhead = self.printer.lookup_object('toolhead')
                # toolhead._calc_print_time()
                mcu = self.printer.lookup_object('mcu')
                reactor = self.printer.get_reactor()
                eventtime = reactor.monotonic()
                print_time = mcu.estimated_print_time(eventtime)
                ch.set_current(tmc_command_helper.prev_cur, tmc_command_helper.prev_hold_cur, print_time + 0.05)


def load_config(config):
    return CfDev(config)
